package cn.inswf.net {
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import flash.utils.ByteArray;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.utils.Dictionary;

	/**
	 * @author lee
	 */
	[Event(name = "complete", type = "flash.events.Event")]
	[Event(name = "ioError", type = "flash.events.IOErrorEvent")]
	[Event(name = "securityError", type = "flash.events.SecurityErrorEvent")]
	[Event(name="progress", type="flash.events.ProgressEvent")]
	public class BaseLoadQueue extends EventDispatcher {
		public var urlRequest : URLRequest;
		protected var _loader : ILoader;
		// 加载器类
		protected var LoaderClass : Class;
		// 加载器最大个数
		protected var _queueMax : int = 3;
		// /当前加载器个数
		protected var _queueCount : int;
		// 请求列表
		protected var _requestList : Array;
		// 请求地址索引
		protected var _urlDict : Dictionary;
		// 可用加载器
		protected var _availableList : Array;
		// 加载总个数
		protected var _count : int;
		protected var _update : Boolean;
		protected var _index : int;
		private var _clone:ByteArray;
		private var _timer:Timer;
		public function BaseLoadQueue(max : int = 3) {
			_requestList = [];
			_queueMax = max;
			_availableList = [];
			_urlDict = new Dictionary();
			_clone=new ByteArray();
			_timer=new Timer(1,1);
			_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timeend);
		}

		private function timeend(event : TimerEvent) : void {
			start();
		}
		public function load(request : URLRequest, priority : int = -1, context : LoaderContext = null):void{
			if (request == null) return;
			var url : String = request.url;
			if (_urlDict[url] != undefined) return;
			if (priority < 0) {
				priority = _index--;
			}
			_urlDict[url] = true;
			var clone : URLRequest = new URLRequest(url);
			clone.contentType = request.contentType;
			_clone.clear();
			_clone.writeObject(request.data);
			_clone.position=0;
			clone.data = _clone.readObject();
			clone.digest = request.digest;
			clone.method = request.method;
			clone.requestHeaders = request.requestHeaders;
			if (clone.requestHeaders != null) {
				clone.requestHeaders = request.requestHeaders.concat();
			}
			var sortRequest : BaseURLRequest = new BaseURLRequest(clone, priority);
			sortRequest.context = context;
			_requestList.push(sortRequest);
			_count = _requestList.length;
			_update = true;
			_timer.start();
		}
		protected function start() : void {
			if (_update) {
				_requestList.sortOn("priority", Array.NUMERIC);
			}
			_update = false;
			loadNext();
		}

		public final function stop() : void {
			var len : int = _requestList.length;
			while (len--) {
				var requestdata : BaseURLRequest = _requestList[len];
				var request : URLRequest = requestdata.request;
				delete _urlDict[request.url];
			}
			_requestList.length = 0;
			for (var url:String in _urlDict) {
				finish(url);
			}
		}

		public final function remove(...urls) : void {
			var len : int = _requestList.length;
			while (len--) {
				var requestdata : BaseURLRequest = _requestList[len];
				var url : String = requestdata.request.url;
				if (urls.indexOf(url) != -1) {
					_requestList.splice(len, 1);
					return;
				}
			}
			_count = _requestList.length;
			loadNext();
		}

		public final function finish(url : String) : void {
			if (_urlDict[url] == undefined) return;
			if (_urlDict[url] == true) {
				remove(url);
				return;
			}
			_count = _requestList.length;
			_loader = _urlDict[url];
			if (_loader) {
				_loader.stopload();
				_availableList.push(_loader);
			}
			delete _urlDict[url];
			loadNext();
		}

		public final function get count() : int {
			return _count;
		}

		public final function set max(value : int) : void {
			var add : Boolean = value > _queueMax;
			_queueMax = value;
			if (add) {
				loadNext();
			}
		}

		protected final function loadNext() : void {
			if (_requestList.length == 0) {
				_index = 0;
				return;
			}
			initLoader();
			_loader = _availableList.pop();
			if (_loader == null) return;
			var requestdata : BaseURLRequest = _requestList.pop();
			if (requestdata == null) return;
			var request : URLRequest = requestdata.request;
			_urlDict[request.url] = _loader;
			_loader.start(request, requestdata.context);
			loadNext();
		}

		private function initLoader() : void {
			if (_queueCount < _queueMax) {
				_loader = new LoaderClass();
				if (_loader) {
					_availableList.push(_loader);
					_queueCount++;
					setEvent(_loader.dispatcher, true);
				}
			} else if (_queueCount > _queueMax) {
				_loader = _availableList.pop();
				if (_loader) {
					_queueCount--;
					setEvent(_loader.dispatcher, false);
				}
			}
		}

		private function setEvent(value : EventDispatcher, add : Boolean) : void {
			if (value == null) return;
			if (add) {
				value.addEventListener(IOErrorEvent.IO_ERROR, _ioHandler);
				value.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityHandler);
				value.addEventListener(Event.OPEN, _openHandler);
				value.addEventListener(ProgressEvent.PROGRESS, _progressHandler);
				value.addEventListener(Event.COMPLETE, _completeHandler);
			} else {
				value.removeEventListener(IOErrorEvent.IO_ERROR, _ioHandler);
				value.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityHandler);
				value.removeEventListener(Event.OPEN, _openHandler);
				value.removeEventListener(ProgressEvent.PROGRESS, _progressHandler);
				value.removeEventListener(Event.COMPLETE, _completeHandler);
			}
		}

		protected function _ioHandler(e : IOErrorEvent) : void {
			trigger(e, true);
		}

		protected function _openHandler(e : Event) : void {
			trigger(e);
		}

		protected function _securityHandler(e : SecurityErrorEvent) : void {
			trigger(e, true);
		}

		protected function _progressHandler(e : ProgressEvent) : void {
			trigger(e);
		}

		protected function _completeHandler(e : Event) : void {
			trigger(e, true);
		}

		protected function trigger(e : Event, complete : Boolean = false) : void {
			_loader = e.target as ILoader;
			if (_loader == null) return;
			urlRequest = _loader.urlRequest;
			var url : String = urlRequest.url;
			if (_urlDict[url] == undefined) return;
			dispatchEvent(e);
			if (complete) {
				finish(url);
			}
		}
	}
}
